import java.util.ArrayList;
import java.util.Scanner;

public class Linker {
	private static int headerCount;
	private static int endCount;
	private static int numOfLRecords;
	private static int numOfTRecords;
	private static int length;
	private static String moduleName1;
	private static String moduleName2;
	private static String moduleName3;
	private static String adjustment;
	private static int adjustmentValue;
	private static int runningEntryCount;
	private static Scanner scanLine;
	private static boolean duplicateHeader = false;
	protected static ErrorHandler2 errors = new ErrorHandler2();
	protected static ErrorHandler2	textErrors = new ErrorHandler2();
	private static Integer textNumber = -1;
	private static ArrayList<String> entryArray = new ArrayList<String>(0);

	private Linker() {}

	/**
	 * @description runLinker reads in the object file, breaks it down,
	 *  and creates the data objects used in the loader.
	 * @callsequence 
	 * @inparam objectFileText the object file we are going to break down.
	 * @outparam none
	 * @errorstested See JUnit test cases
	 * @errorsgenerated See errata report
	 * @author Travis Casper
	 * @createdate 11/19/09
	 * @modlog <p>
	 *         <ul>
	 *         Who/When/Why
	 *         <li>Travis - 11/19 - Created
	 *         <li>Jamie - 11/21 - added some error detection
	 *         <li>Jamie - 11/23 - added more error detection
	 *         <li>Jamie - 11/28 - finished up error detection
	 *         </ul>
	 *         <p>
	 *         Coding Standards Met: "Signed Code Leader(Jaron)"
	 *         <p>
	 *         Testing Standards Met: "Signed Test Leader(Jamie)"
	 */
	public static void runLinker(String objectFileText) {
		headerCount = 0;
		endCount = 0;
		numOfLRecords = 0;
		numOfTRecords = 0;
		length = 0;
		runningEntryCount=0;
		moduleName1 = "";
		moduleName2 = "";
		moduleName3 = "";
		adjustment = "";
		Scanner scan = new Scanner(objectFileText);
		while (scan.hasNext()) {
			String nextLine = scan.nextLine();
			nextLine = nextLine.trim();
			//Main2.appendDebugText(nextLine + "\n");
			System.out.println(nextLine);
			runLine(nextLine);
			System.out.println();
		}
		scan.close();
		Loader.runLoader();
	}


	private static void runLine(String line) {
		scanLine = new Scanner(line);
		scanLine.useDelimiter("\\|");
		if (scanLine.hasNext()) {
			// First Item should be Record Type
			String recordType = scanLine.next();
			//Main2.appendDebugText(recordType + "\n");
			System.out.println("Record Type = " + recordType);
			if(duplicateHeader==false){
				Main2.appendDebugText(line);
			}	
			checkRecordType(recordType);
		}
	}
	private static boolean checkRecordType(String recordType) {

		if (headerCount > 3) {
			return false;
		} else {
			if (recordType.equalsIgnoreCase("H")) {
				headerCount++;
				runHeaderRecord();
			} else if (recordType.equalsIgnoreCase("L")) {
				if(duplicateHeader==true){
					return false;
				}
				runLinkingRecord();
			} else if (recordType.equalsIgnoreCase("T")) {
				if(duplicateHeader==true){
					return false;
				}
				textNumber++;
				runTextRecord();
			} else if (recordType.equalsIgnoreCase("E")) {
				if(duplicateHeader==true){
					return false;
				}
				endCount++;
				if (endCount > headerCount) {

					errors.addToErrorList("0", "7", "Having more end records than header records is not allowed.");
					Main2.appendDebugText(errors.removeFirstError());
					// ERROR: More End Records than Header records...This cannot be
					return false;
				}
				runEndRecord();
			} 
			else {
				errors.addToErrorList("0", "9");
				Main2.appendDebugText(errors.removeFirstError());
				return false;
			}
			return true;
		}
	}

	private static void runTextRecord() {
		String address = "";
		String macCode = "";
		String relocationS1 = "";
		String symbolS1 = "";
		String operatorS1 = "";
		String relocationS2 = "";
		String symbolS2 = "";
		String operatorS2 = "";
		String relocationS3 = "";
		String symbolS3 = "";
		String operatorS3 = "";
		String moduleName = "";


		if (scanLine.hasNext()) {
			address = scanLine.next();
			if(isValidHex(address)==false){
				//ERROR
				errors.addToErrorList("0", "16", "The address hex was not in the correct format.");
				Main2.appendDebugText(errors.removeFirstError());
			}
			//Main2.appendDebugText(address + "\n");
			System.out.print("Address = " + address + "\n");
			if (scanLine.hasNext()) {
				macCode = scanLine.next();
				if(isValidHex(macCode)==false){
					//ERROR
					errors.addToErrorList("0", "16", "The data word hex was not in the correct format.");
					Main2.appendDebugText(errors.removeFirstError());
				}
				//Main2.appendDebugText(macCode + "\n");
				System.out.print("Machine Code = " + macCode + "\n");
				//Main2.appendDebugText("Hex Code Read in:\t" + macCode);
				if (scanLine.hasNext()) {
					relocationS1 = scanLine.next();
					//Main2.appendDebugText(relocationS1 + "\n");
					System.out.print("Relocation Code for S1 = " + relocationS1 + "\n");
					if (scanLine.hasNext()) {
						String nextItem = scanLine.next();
						if (nextItem.equalsIgnoreCase("\u002b") || nextItem.equalsIgnoreCase("\u002d")) {
							operatorS1 = nextItem;
							//Main2.appendDebugText(operatorS1 + "\n");
							System.out.print("Operator for S1 = " + operatorS1 + "\n");
						} else {
							textErrors.addToErrorList(Integer.toString(textNumber), "2", "The operator was improperly formatted.");
							errors.addToErrorList("0", "2", "The operator was improperly formatted.");
							Main2.appendDebugText(errors.removeFirstError());
							// ERROR: Unproperly formatted Operator
						}
						if (scanLine.hasNext()) {
							symbolS1 = scanLine.next();
							//Main2.appendDebugText(symbolS1 + "\n");
							System.out.print("Symbol for S1 = " + symbolS1 + "\n");
							if (scanLine.hasNext()) {
								nextItem = scanLine.next();
								if (nextItem.equalsIgnoreCase(moduleName1) || nextItem.equalsIgnoreCase(moduleName2) || nextItem.equalsIgnoreCase(moduleName3)) {
									moduleName = nextItem;
									//Main2.appendDebugText(moduleName + "\n");
									System.out.print("ModuleName = " + moduleName + "\n");	
									address = adjustAddress(address);
									if (symbolS1.equalsIgnoreCase("*")) {
										symbolS1 = address;
										relocationS1 = "A";
									}
									Loader.addTextRecord(address, macCode, relocationS1, operatorS1, symbolS1, moduleName, adjustmentValue);
								} else {
									relocationS2 = nextItem;
									//Main2.appendDebugText(relocationS2 + "\n");
									System.out.print("Relocation Code for S2 = " + relocationS2 + "\n");
								}
								if (scanLine.hasNext()) {
									nextItem = scanLine.next();
									if (nextItem.equalsIgnoreCase("\u002b") || nextItem.equalsIgnoreCase("\u002d")) {
										operatorS2 = nextItem;
										//Main2.appendDebugText(operatorS2 + "\n");
										System.out.print("Operator for S2 = " + operatorS2 + "\n");
									} else {
										textErrors.addToErrorList(Integer.toString(textNumber), "2", "The operator was improperly formatted.");
										errors.addToErrorList("0", "2", "The operator was improperly formatted.");
										Main2.appendDebugText(errors.removeFirstError());
										// ERROR: Unproperly formatted Operator
									}
									if (scanLine.hasNext()) {
										symbolS2 = scanLine.next();
										//Main2.appendDebugText(symbolS2 + "\n");
										System.out.print("Symbol for S2 = " + symbolS2 + "\n");
										if (scanLine.hasNext()) {
											nextItem = scanLine.next();
											if (nextItem.equalsIgnoreCase(moduleName1) || nextItem.equalsIgnoreCase(moduleName2) || nextItem.equalsIgnoreCase(moduleName3)) {
												moduleName = nextItem;
												//Main2.appendDebugText(moduleName + "\n");
												System.out.print("ModuleName = " + moduleName + "\n");	
												address = adjustAddress(address);
												if (symbolS1.equalsIgnoreCase("*")) {
													symbolS1 = address;
													relocationS1 = "A";
												}
												if (symbolS2.equalsIgnoreCase("*")) {
													symbolS2 = address;
													relocationS2 = "A";
												}
												Loader.addTextRecord(address, macCode, relocationS1, operatorS1, symbolS1, relocationS2, operatorS2, symbolS2, moduleName, adjustmentValue);
											} else {
												relocationS3 = nextItem;
												//Main2.appendDebugText(relocationS3 + "\n");
												System.out.print("Relocation Code for S3 = " + relocationS3 + "\n");
											}
											if (scanLine.hasNext()) {
												nextItem = scanLine.next();
												if (nextItem.equalsIgnoreCase("\u002b") || nextItem.equalsIgnoreCase("\u002d")) {
													operatorS3 = nextItem;
													//Main2.appendDebugText(operatorS3 + "\n");
													System.out.print("Operator for S3 = " + operatorS3 + "\n");
												} else {
													textErrors.addToErrorList(Integer.toString(textNumber), "2", "The operator was improperly formatted.");
													errors.addToErrorList("0", "2", "The operator was improperly formatted.");
													Main2.appendDebugText(errors.removeFirstError());
													// ERROR: Unproperly formatted Operator
												}
												if (scanLine.hasNext()) {
													symbolS3 = scanLine.next();
													//Main2.appendDebugText(symbolS3 + "\n");
													System.out.print("Symbol for S3 = " + symbolS3 + "\n");
													if (scanLine.hasNext()) {
														nextItem = scanLine.next();
														if (nextItem.equalsIgnoreCase(moduleName1) || nextItem.equalsIgnoreCase(moduleName2) || nextItem.equalsIgnoreCase(moduleName3)) {
															moduleName = nextItem;
															//Main2.appendDebugText(moduleName + "\n");
															System.out.print("ModuleName = " + moduleName + "\n");	
															address = adjustAddress(address);
															if (symbolS1.equalsIgnoreCase("*")) {
																symbolS1 = address;
																relocationS1 = "A";
															}
															if (symbolS2.equalsIgnoreCase("*")) {
																symbolS2 = address;
																relocationS2 = "A";
															}
															if (symbolS3.equalsIgnoreCase("*")) {
																symbolS3 = address;
																relocationS3 = "A";
															}
															Loader.addTextRecord(address, macCode, relocationS1, operatorS1, symbolS1, relocationS2, operatorS2, symbolS2, relocationS3, operatorS3, symbolS3, moduleName, adjustmentValue);
														} else {
															textErrors.addToErrorList(Integer.toString(textNumber), "2", "The module name was not given.");
															errors.addToErrorList("0", "2", "The module name was not given.");
															Main2.appendDebugText(errors.removeFirstError());
															// ERROR: Undefined Module Name
														}
													}
												}
											}
										}
									}
								}
							}
						}
					}
				}
			}
		}

	}

	private static void runLinkingRecord() {
		String entryName = "";
		String entryAddrStr = "";
		String moduleName = "";
		String computedAdr = "";

		if (scanLine.hasNext()) {
			entryName = scanLine.next();
			Boolean validLabel = isValidLabelType(entryName);
			if(entryArray.contains(entryName)){
				errors.addToErrorList("0", "13");
				Main2.appendDebugText(errors.removeFirstError());
			}
			else if(validLabel==false){
				errors.addToErrorList("0", "14");
				Main2.appendDebugText(errors.removeFirstError());
			}
			else if(LoadMap.symbolIsDefined(entryName)){
				errors.addToErrorList("0", "15", entryName+"has already been used.");
				Main2.appendDebugText(errors.removeFirstError());
			}
			else{
				entryArray.add(entryName);			
				//Main2.appendDebugText(entryName + "\n");
				System.out.print("Entry Name = " + entryName + "\n");
				if (scanLine.hasNext()) {
					entryAddrStr = scanLine.next();
					if(isValidHex(entryAddrStr)==false){
						//ERROR
						errors.addToErrorList("0", "16");
						Main2.appendDebugText(errors.removeFirstError());
					}
					//Main2.appendDebugText(entryAddStr + "\n");
					System.out.print("Entry Address in HEX = " + entryAddrStr + "\n");
					if (scanLine.hasNext()) {
						moduleName = scanLine.next();
						//Main2.appendDebugText(time + "\n");
						System.out.print("Module Name = " + moduleName + "\n");
						if (scanLine.hasNext()) {
							errors.addToErrorList("0", "4", "The Linking Record contained too many fields.");
							Main2.appendDebugText(errors.removeFirstError());
							//ERROR: Header Record has too many items
							System.out.println("ERROR: too many items");
						}
					} else {
						errors.addToErrorList("0", "4", "No module name was present.");
						Main2.appendDebugText(errors.removeFirstError());
						System.out.println("ERROR: No Module Name");
					}
				} else {
					errors.addToErrorList("0", "4");
					Main2.appendDebugText(errors.removeFirstError());
					System.out.println("ERROR: No Entry Address");
				}
			} 
		}
		else {
			errors.addToErrorList("0", "4");
			Main2.appendDebugText(errors.removeFirstError());
			System.out.println("ERROR: No Entry Name");
		}
		Integer entryAdr = 0;
		try{
			entryAdr = Integer.parseInt(entryAddrStr, 16);
		}
		catch(NumberFormatException e){
			//ERROR
			//	bodyErrors.addToErrorList(entryAddrStr, "4");
		}

		computedAdr = computeEntryAddress(entryAdr);
		LoadMap.addSymbol(entryName, "Entry_Sym", entryAddrStr, "-", computedAdr, "n/a");
		runningEntryCount++;
		if(runningEntryCount>numOfLRecords){
			errors.addToErrorList("0", "18");
			Main2.appendDebugText(errors.removeFirstError());
		}
	}


	private static void runHeaderRecord() {
		String moduleName = "";
		String moduleLengthStr = "";
		String ldAddrStr = "";
		String stAddrStr = "";
		String computedAdr = "";
		Integer moduleLengthDec=0;

		if (scanLine.hasNext()) {
			moduleName = scanLine.next();
			//Main2.appendDebugText(moduleName + "\n");
			System.out.print("Module Name = " + moduleName + "\n");
			if (scanLine.hasNext()) {
				String date = scanLine.next();
				//Main2.appendDebugText(date + "\n");
				System.out.print("Date = " + date + "\n");
				if (scanLine.hasNext()) {
					String time = scanLine.next();
					//Main2.appendDebugText(time + "\n");
					System.out.print("Time = " + time + "\n");
					if (scanLine.hasNext()) {
						moduleLengthStr = scanLine.next();
						//Main2.appendDebugText(moduleLengthStr + "\n");
						System.out.print("Module Length = " + moduleLengthStr + "\n");
						try{
							if(isValidHex(moduleLengthStr)==false){
								//ERROR
								errors.addToErrorList("0", "16");
								Main2.appendDebugText(errors.removeFirstError());
							}
							moduleLengthDec = Integer.parseInt(moduleLengthStr, 16);
							if(moduleLengthDec > 4096){
								errors.addToErrorList("0", "17", "The module length is greater than the amount of memory available.");
								Main2.appendDebugText(errors.removeFirstError());

							}
						}catch(NumberFormatException e){
							errors.addToErrorList("0", "3", "The header did not contain the module length.");
							Main2.appendDebugText(errors.removeFirstError());
						}
						if (scanLine.hasNext()) {
							ldAddrStr = scanLine.next();
							//Main2.appendDebugText(ldAddrStr + "\n");
							System.out.print("Load Address = " + ldAddrStr + "\n");
							Integer ldAddrDec=0;
							try{
								if(isValidHex(ldAddrStr)==false){
									//ERROR
									errors.addToErrorList("0", "16");
									Main2.appendDebugText(errors.removeFirstError());
								}
								ldAddrDec = Integer.parseInt(ldAddrStr, 16);
								if(ldAddrDec > 4096){
									errors.addToErrorList("0", "17", "The load address is outside the range of available memory.");
									Main2.appendDebugText(errors.removeFirstError());
								}
							}
							catch(NumberFormatException e){
								errors.addToErrorList("0", "3", "The header did not contain the load address.");
								Main2.appendDebugText(errors.removeFirstError());
							}
							if (scanLine.hasNext()) {
								try{
									String numOfLRecordsString = scanLine.next();
									if(isValidHex(numOfLRecordsString)==false){
										//ERROR
										errors.addToErrorList("0", "16");
										Main2.appendDebugText(errors.removeFirstError());
									}
									numOfLRecords = Integer.parseInt(numOfLRecordsString, 16);
									//Main2.appendDebugText(numOfLRecords + "\n");
								}catch(NumberFormatException e){
									//ERROR add this in
									errors.addToErrorList("0", "3", "The header record did not contain the number of linking records.");
									Main2.appendDebugText(errors.removeFirstError());
									System.out.println("ERROR: No Number of Linking Records");
								}

								System.out.print("Number of Linking Records = " + numOfLRecords + "\n");
								if (scanLine.hasNext()) {
									String numOfTRecordsString = scanLine.next();
									if(isValidHex(numOfTRecordsString)==false){
										//ERROR
										errors.addToErrorList("0", "16");
										Main2.appendDebugText(errors.removeFirstError());
									}
									try{
										numOfTRecords = Integer.parseInt(numOfTRecordsString, 16);
										//Main2.appendDebugText(numOfTRecords + "\n");
										System.out.print("Number of Text Records = " + numOfTRecords + "\n");
									}catch(NumberFormatException e){
										//ERROR add this in
										errors.addToErrorList("0", "3", "The header record did not contain the number of text records.");
										Main2.appendDebugText(errors.removeFirstError());
										System.out.println("ERROR: No Number of Text Records");
									}
									if(numOfTRecords>moduleLengthDec){
										errors.addToErrorList("0", "17", "The number of text records was greater than the module length. How is that possible?");
										Main2.appendDebugText(errors.removeFirstError());
									}

									if (scanLine.hasNext()) {
										stAddrStr = scanLine.next();
										try{
											if(isValidHex(stAddrStr)==false){
												//ERROR
												errors.addToErrorList("0", "16");
												Main2.appendDebugText(errors.removeFirstError());
											}
											Integer stAddrDec = Integer.parseInt(stAddrStr, 16);
											if((stAddrDec+ldAddrDec) > 4096){
												errors.addToErrorList("0", "17", "The load address is outside the range of available memory.");
												Main2.appendDebugText(errors.removeFirstError());
											}
											if(ldAddrDec>stAddrDec){
												errors.addToErrorList("0", "17", "The load address cannot be greater than the start address.");
												Main2.appendDebugText(errors.removeFirstError());
											}
										}
										catch(NumberFormatException e){
											errors.addToErrorList("0", "3", "The header did not contain the start address.");
											Main2.appendDebugText(errors.removeFirstError());
										}
										//Main2.appendDebugText(stAddrStr + "\n");
										System.out.print("Start Address = " + stAddrStr + "\n");
										if (scanLine.hasNext()) {
											String tressel = scanLine.next();
											//Main2.appendDebugText(tressel + "\n");
											System.out.print("TRESSEL = " + tressel + "\n");
											if (scanLine.hasNext()) {
												String verNum = scanLine.next();
												//Main2.appendDebugText(verNum + "\n");
												System.out.print("Version # = " + verNum + "\n");
												if (scanLine.hasNext()) {
													String revNum = scanLine.next();
													//Main2.appendDebugText(revNum + "\n");
													System.out.print("Revision # = " + revNum + "\n");
													if (scanLine.hasNext()) {
														errors.addToErrorList("0", "3", "The Header Record contained too many fields.");
														Main2.appendDebugText(errors.removeFirstError());
														//ERROR: Header Record has too many items
														System.out.println("ERROR: too many items");
													}
												} else {
													errors.addToErrorList("0", "3", "No revision number was contained in the header record.");
													Main2.appendDebugText(errors.removeFirstError());
													System.out.println("ERROR: No Revision #");
												}
											} else {
												errors.addToErrorList("0", "3", "No version # was contained in the header record.");
												Main2.appendDebugText(errors.removeFirstError());
												System.out.println("ERROR: No Version #");
											}
										} else {
											errors.addToErrorList("0", "3", "The 'TRESSEL' field did not contain anything.");
											Main2.appendDebugText(errors.removeFirstError());
											System.out.println("ERROR: No TRESSEL");
										}
									} else {
										errors.addToErrorList("0", "3", "No start address was contained in the header record.");
										Main2.appendDebugText(errors.removeFirstError());
										System.out.println("ERROR: No Start Address");
									}
								} else {
									errors.addToErrorList("0", "3", "The header record did not contain the number of text records.");
									Main2.appendDebugText(errors.removeFirstError());
									System.out.println("ERROR: No Number of Text Records");
								}
							} else {
								errors.addToErrorList("0", "3", "The header record did not contain the number of linking records.");
								Main2.appendDebugText(errors.removeFirstError());
								System.out.println("ERROR: No Number of Linking Records");
							}
						} else {
							errors.addToErrorList("0", "3", "No load address was contained in the header record.");
							Main2.appendDebugText(errors.removeFirstError());
							System.out.println("ERROR: No Load Address");
						}
					} else {
						errors.addToErrorList("0", "3", "No program length was contained in the header record.");
						Main2.appendDebugText(errors.removeFirstError());
						System.out.println("ERROR: No Program Length");
					}
				} else {
					errors.addToErrorList("0", "3", "The time of compilation was not contained in the header file.");
					Main2.appendDebugText(errors.removeFirstError());
					System.out.println("ERROR: No Time");
				}
			} else {
				errors.addToErrorList("0", "3", "The date of compilation was not contained in the header file.");
				Main2.appendDebugText(errors.removeFirstError());
				System.out.println("ERROR: No Date");
			}
		} else {
			// ERROR: Header Record should have Module Name
			errors.addToErrorList("0", "3", "The module name was not contained in the header record.");
			Main2.appendDebugText(errors.removeFirstError());
			System.out.println("ERROR: No Module Name");
		}
		Integer stAdr=0;
		Integer ldAdr=0;
		Integer moduleLength =0;
		try{
			stAdr = Integer.parseInt(stAddrStr, 16);
		}catch(NumberFormatException e){
			//ERROR
			errors.addToErrorList("0", "8");
			Main2.appendDebugText(errors.removeFirstError());
		}
		try{
			ldAdr = Integer.parseInt(ldAddrStr, 16);
		}catch(NumberFormatException e){
			//ERROR
			errors.addToErrorList("0", "8");
			Main2.appendDebugText(errors.removeFirstError());
		}
		try{
			moduleLength = Integer.parseInt(moduleLengthStr, 16);
		}catch(NumberFormatException e){
			//ERROR
			errors.addToErrorList("0", "8");
			Main2.appendDebugText(errors.removeFirstError());
		}




		computedAdr = computeModuleAddress(moduleName, ldAdr, moduleLength);
		if(duplicateHeader==false){
			LoadMap.addSymbol(moduleName, "Pgm_Name", ldAddrStr, moduleLengthStr, computedAdr, adjustment);
			if (headerCount == 1) {
				stAdr += adjustmentValue;
				ldAdr += adjustmentValue;
				LoadFile.startLoadFile(moduleName, stAdr, moduleLength, ldAdr);
			}
		}
	}

	private static void runEndRecord() {
		String numOfRecordsStr = "";
		String moduleName = "";

		if (scanLine.hasNext()) {
			numOfRecordsStr = scanLine.next();
			if(isValidHex(numOfRecordsStr)==false){
				//ERROR
				errors.addToErrorList("0", "16");
				Main2.appendDebugText(errors.removeFirstError());
			}
			int  numOfRecords =0;
			try{
				numOfRecords = Integer.parseInt(numOfRecordsStr, 16);
			}catch(NumberFormatException e){
				//ERROR
				errors.addToErrorList("0", "8");
				Main2.appendDebugText(errors.removeFirstError());
			}

			//Main2.appendDebugText(numOfRecordsStr + "\n");
			System.out.print("Total Number of Records = " + numOfRecords + "\n");
			if (scanLine.hasNext()) {
				moduleName = scanLine.next();
				//Main2.appendDebugText(entryAddStr + "\n");
				System.out.print("Module Name = " + moduleName + "\n");
				if (scanLine.hasNext()) {
					errors.addToErrorList("0", "5", "The end record contains too many fields.");
					Main2.appendDebugText(errors.removeFirstError());
					//ERROR: Header Record has too many items
					System.out.println("ERROR: too many items");
				}
			} else {
				errors.addToErrorList("0", "5", "The end record did not contain a module name.");
				Main2.appendDebugText(errors.removeFirstError());
				System.out.println("ERROR: No Module Name");
			}
		} else {
			errors.addToErrorList("0", "5", "The end record did not have a total number of records.");
			Main2.appendDebugText(errors.removeFirstError());
			System.out.println("ERROR: No Total Number of Records");
		}
	}

	private static String adjustAddress(String address) {
		int addressValue=0;
		int adjustmentValue=0;
		int adjustedAddressValue =0;
		try{
			addressValue = Integer.parseInt(address, 16);
		}catch(NumberFormatException e){
			//ERROR
			errors.addToErrorList("0", "8");
			Main2.appendDebugText(errors.removeFirstError());
		}try{
			adjustmentValue = Integer.parseInt(adjustment);
		}catch(NumberFormatException e){
			//ERROR
			errors.addToErrorList("0", "8");
			Main2.appendDebugText(errors.removeFirstError());
		}try{
			adjustedAddressValue = 0;
		}catch(NumberFormatException e){
			//ERROR
			errors.addToErrorList("0", "8");
			Main2.appendDebugText(errors.removeFirstError());
		}
		String adjustedAddress = "";
		adjustedAddressValue = addressValue + adjustmentValue;
		adjustedAddress = Integer.toString(adjustedAddressValue);		
		return adjustedAddress;
	}


	private static String computeModuleAddress(String moduleName, Integer assemblerLocation, Integer moduleLength) {
		int computedModuleAdr = 0;
		if (headerCount == 1) {
			moduleName1 = moduleName;
			length = moduleLength;
			computedModuleAdr = 0;
		} else if (headerCount == 2) {
			if(LoadMap.symbolIsDefined(moduleName)){
				duplicateHeader = true;
				headerCount--;
				errors.addToErrorList("0", "15", moduleName+" has already been used.");
				Main2.appendDebugText(errors.removeFirstError());
			}
			else if(!moduleName.equalsIgnoreCase(moduleName1)){
				moduleName2 = moduleName;
				String previousAdrStr = LoadMap.returnLinkerLocation(moduleName1);
				int previousAdr =0;
				try{
					previousAdr = Integer.parseInt(previousAdrStr, 16);
				}catch(NumberFormatException e){
					//ERROR
					errors.addToErrorList("0", "8");
					Main2.appendDebugText(errors.removeFirstError());
				}
				computedModuleAdr = previousAdr + length;
				length = moduleLength;
				duplicateHeader = false;
			}
			else{
				duplicateHeader = true;
				headerCount--;
				errors.addToErrorList("0", "6", moduleName+" was a duplicate program name, and was not run a second time.");
				Main2.appendDebugText(errors.removeFirstError());
			}
		} else if (headerCount == 3) {
			if(LoadMap.symbolIsDefined(moduleName)){
				duplicateHeader = true;
				headerCount--;
				errors.addToErrorList("0", "15", moduleName+" has already been used.");
				Main2.appendDebugText(errors.removeFirstError());
			}
			else if(!moduleName.equalsIgnoreCase(moduleName1)&& !moduleName.equalsIgnoreCase(moduleName2)){
				moduleName3 = moduleName;
				String previousAdrStr = LoadMap.returnLinkerLocation(moduleName2);
				int previousAdr=0;
				try{
					previousAdr = Integer.parseInt(previousAdrStr, 16);
				}catch(NumberFormatException e){
					//ERROR
					errors.addToErrorList("0", "8");
					Main2.appendDebugText(errors.removeFirstError());
				}
				computedModuleAdr = previousAdr + length;
				length = moduleLength;
				duplicateHeader = false;
			}
			else{
				duplicateHeader = true;
				headerCount--;
				//ERROR
				errors.addToErrorList("0", "6", moduleName+" was a duplicate program name, and was not run a second time.");
				Main2.appendDebugText(errors.removeFirstError());
			}
		}
		adjustmentValue = computedModuleAdr - assemblerLocation;
		adjustment = Integer.toString(adjustmentValue);
		String computedModuleAdrStr = Integer.toHexString(computedModuleAdr);
		computedModuleAdrStr = formatFourDigitHex(computedModuleAdrStr);
		return computedModuleAdrStr;
	}

	private static String computeEntryAddress(Integer entryAdr) {
		int computedEntryAdr = 0;
		String computedModuleAdr = "";
		String assemblerModuleAdr = "";

		if (headerCount == 1) {
			computedModuleAdr = LoadMap.returnLinkerLocation(moduleName1);
			assemblerModuleAdr = LoadMap.returnAssemblerLocation(moduleName1);
		} else if (headerCount == 2) {
			computedModuleAdr = LoadMap.returnLinkerLocation(moduleName2);
			assemblerModuleAdr = LoadMap.returnAssemblerLocation(moduleName2);
		} else if (headerCount == 3) {
			computedModuleAdr = LoadMap.returnLinkerLocation(moduleName3);
			assemblerModuleAdr = LoadMap.returnAssemblerLocation(moduleName3);
		}
		int assemblerModuleAdrValue = 0;
		int computedModuleAdrValue = 0;
		try{
			assemblerModuleAdrValue = Integer.parseInt(assemblerModuleAdr, 16);
		}catch(NumberFormatException e){
			//ERROR
			errors.addToErrorList("0", "8");
			Main2.appendDebugText(errors.removeFirstError());
		}	
		try{
			computedModuleAdrValue = Integer.parseInt(computedModuleAdr, 16);
		}catch(NumberFormatException e){
			//ERROR
			errors.addToErrorList("0", "8");
			Main2.appendDebugText(errors.removeFirstError());
		}
		computedEntryAdr = computedModuleAdrValue - assemblerModuleAdrValue + entryAdr;

		String computedEntryAdrStr = Integer.toHexString(computedEntryAdr);
		return computedEntryAdrStr;
	}

	private static String formatFourDigitHex(String incomingText) {
		while (incomingText.length() < 4) {
			incomingText = "0" + incomingText;
		}
		return incomingText;
	}

	private static Boolean isValidLabelType(String label) {
		// make sure the label has a valid length
		if ((label.length() > 64) || (label.length() < 2)) {
			return false;
		}

		// make sure the label starts with a letter
		if (!(Character.isLetter(label.charAt(0)))) {
			return false;
		}

		// make sure the label only contains valid characters
		for (int i = 0; i < label.length(); i++) {
			if (!((Character.isLetterOrDigit(label.charAt(i)))
					|| (label.charAt(i) == '.') || (label.charAt(i) == '_') || (label
							.charAt(i) == '-'))) {
				return false;
			}
		}
		return true;
	}
	private static Boolean isValidHex(String operand){
		// remove 0x
		if(operand.length()>0){
			if ((operand.charAt(0) == '0')
					&& ((operand.charAt(1) == 'x') || (operand.charAt(1) == 'X'))) {
				operand = operand.substring(2);
			}
			// HEX = a hex string up to 6 bytes
			if (operand.length() > 6) {
				return false;
			}
			// make sure all chars are in range
			for (int i = 0; i < operand.length(); i++) {
				if (!((Character.isDigit(operand.charAt(i)))
						|| (operand.charAt(i) == 'A')
						|| (operand.charAt(i) == 'B')
						|| (operand.charAt(i) == 'C')
						|| (operand.charAt(i) == 'D')
						|| (operand.charAt(i) == 'E')
						|| (operand.charAt(i) == 'F')
						|| (operand.charAt(i) == 'a')
						|| (operand.charAt(i) == 'b')
						|| (operand.charAt(i) == 'c')
						|| (operand.charAt(i) == 'd')
						|| (operand.charAt(i) == 'e') 
						|| (operand.charAt(i) == 'f'))) {
					return false;
				}
			}
			return true;
		}
		return false;
	}
}
